04 os.path路径处理
处理文件路径是编程中最常见的操作之一。你想读取一个配置文件,得知道它的完整路径;想把上传的文件保存到指定目录,得拼接路径;想判断用户给的路径是不是一个真实存在的文件,也得用路径操作。
os.path是Python处理路径的传统方式,它提供了一组函数来拼接、拆分、检查路径。虽然现在有更现代的pathlib模块,但os.path的使用率依然非常高,很多老项目和第三方库都在用。
一、路径拼接
1.1 os.path.join()
把多个路径段拼接成一个完整路径,自动处理路径分隔符。
python
import os.path
# 拼接路径
os.path.join("data", "config", "settings.json")
# 'data/config/settings.json' (Linux/macOS)
# 'data\\config\\settings.json' (Windows)
# 可以拼接任意多的路径段
os.path.join("/Users/apple", "project", "data", "file.txt")
# '/Users/apple/project/data/file.txt'
# 绝对路径会覆盖前面的部分
os.path.join("data", "/tmp", "file.txt")
# '/tmp/file.txt'
# 空字符串会保留分隔符
os.path.join("data", "", "file.txt")
# 'data/file.txt'为什么不用字符串拼接?
python
# 不推荐:手动拼接路径
path = "data" + "/" + "file.txt"
# 推荐:用os.path.join()
path = os.path.join("data", "file.txt")原因很简单:Windows用反斜杠\,Linux/macOS用正斜杠/。os.path.join()会自动处理这个差异。
二、路径拆分
2.1 os.path.basename()
获取路径的最后一部分(文件名或目录名)。
python
import os.path
os.path.basename("/Users/apple/data/file.txt")
# 'file.txt'
os.path.basename("/Users/apple/data/")
# '' (以分隔符结尾时返回空字符串)
os.path.basename("/Users/apple/data")
# 'data'2.2 os.path.dirname()
获取路径的目录部分(去掉最后一部分)。
python
import os.path
os.path.dirname("/Users/apple/data/file.txt")
# '/Users/apple/data'
os.path.dirname("/Users/apple/data/")
# '/Users/apple/data'
os.path.dirname("/Users/apple/data")
# '/Users/apple'
os.path.dirname("file.txt")
# '' (没有目录部分时返回空字符串)2.3 os.path.split()
同时获取目录和文件名,返回元组。
python
import os.path
os.path.split("/Users/apple/data/file.txt")
# ('/Users/apple/data', 'file.txt')
# 等价于
dirpath = os.path.dirname(path)
filename = os.path.basename(path)2.4 os.path.splitext()
分离文件名和扩展名。
python
import os.path
os.path.splitext("file.txt")
# ('file', '.txt')
os.path.splitext("archive.tar.gz")
# ('archive.tar', '.gz')
os.path.splitext("/Users/apple/data/file.txt")
# ('/Users/apple/data/file', '.txt')
os.path.splitext("Makefile")
# ('Makefile', '') (没有扩展名时返回空字符串)2.5 os.path.splitdrive()
分离驱动器号(Windows)。
python
import os.path
# Windows路径
os.path.splitdrive("C:/Users/apple/data.txt")
# ('C:', '/Users/apple/data.txt')
# 非Windows路径
os.path.splitdrive("/Users/apple/data.txt")
# ('', '/Users/apple/data.txt')三、路径检查
3.1 os.path.exists()
检查路径是否存在(文件或目录都可以)。
python
import os.path
os.path.exists("/Users/apple") # True
os.path.exists("/not/exist/path") # False
os.path.exists("data.txt") # True 或 False(取决于当前目录)3.2 os.path.isfile() / os.path.isdir()
分别检查是文件还是目录。
python
import os.path
os.path.isfile("/Users/apple/data.txt") # True(是文件)
os.path.isfile("/Users/apple/project") # False(是目录)
os.path.isfile("/not/exist") # False(不存在)
os.path.isdir("/Users/apple/project") # True(是目录)
os.path.isdir("/Users/apple/data.txt") # False(是文件)3.3 os.path.islink()
检查是否为符号链接。
python
import os.path
os.path.islink("/usr/local/bin/python")
# 可能是True(如果是符号链接)3.4 os.path.isabs()
检查是否为绝对路径。
python
import os.path
os.path.isabs("/Users/apple/data.txt") # True
os.path.isabs("data.txt") # False
os.path.isabs("./data.txt") # False
os.path.isabs("../data.txt") # False四、路径转换
4.1 os.path.abspath()
获取绝对路径(解析.和..)。
python
import os.path
os.path.abspath(".")
# '/Users/apple/project' (当前目录的绝对路径)
os.path.abspath("data.txt")
# '/Users/apple/project/data.txt'
os.path.abspath("../data.txt")
# '/Users/apple/data.txt'
os.path.abspath("~/data.txt")
# '/Users/apple/project/~/data.txt' (不会展开~)4.2 os.path.realpath()
解析符号链接,获取真实路径。
python
import os.path
# 如果/path是符号链接,realpath会解析到真实目标
os.path.realpath("/usr/local/bin/python")
# '/usr/bin/python3.14'4.3 os.path.normpath()
规范化路径(折叠多余的分隔符和.、..)。
python
import os.path
os.path.normpath("/Users/apple//project/../data/./file.txt")
# '/Users/apple/data/file.txt'
os.path.normpath("./data/../file.txt")
# 'file.txt'
# Windows上还会转为反斜杠
os.path.normpath("C:/Users/apple/data.txt")
# 'C:\\Users\\apple\\data.txt' (Windows)4.4 os.path.relpath()
计算相对路径。
python
import os.path
os.path.relpath("/Users/apple/project", "/Users/apple")
# 'project'
os.path.relpath("/Users/apple/data.txt", "/Users/apple/project")
# '../data.txt'
# 默认相对于当前目录
os.path.relpath("/Users/apple/data.txt")
# 计算从当前目录到目标的相对路径4.5 os.path.expanduser()
展开~为用户主目录。
python
import os.path
os.path.expanduser("~/data.txt")
# '/Users/apple/data.txt'
os.path.expanduser("~otheruser/data.txt")
# '/Users/otheruser/data.txt' (如果存在)
os.path.expanduser("data.txt")
# 'data.txt' (没有~时不变化)4.6 os.path.expandvars()
展开路径中的环境变量。
python
import os
os.environ["MY_DATA"] = "/opt/data"
os.path.expandvars("$MY_DATA/file.txt")
# '/opt/data/file.txt'
os.path.expandvars("${MY_DATA}/file.txt")
# '/opt/data/file.txt'五、文件信息
5.1 os.path.getsize()
获取文件大小(字节)。
python
import os.path
size = os.path.getsize("data.txt")
print(f"文件大小: {size} 字节")
# 人类可读的大小
def format_size(size):
for unit in ['B', 'KB', 'MB', 'GB']:
if size < 1024:
return f"{size:.1f} {unit}"
size /= 1024
return f"{size:.1f} TB"
print(format_size(os.path.getsize("data.txt")))5.2 文件时间
python
import os.path
import time
# 最后修改时间
mtime = os.path.getmtime("data.txt")
print(f"修改时间: {time.ctime(mtime)}")
# 最后访问时间
atime = os.path.getatime("data.txt")
# 创建时间(Windows)/ 元数据修改时间(Unix)
ctime = os.path.getctime("data.txt")5.3 os.path.samefile()
检查两个路径是否指向同一个文件。
python
import os.path
os.path.samefile("/Users/apple/data.txt", "/Users/apple/../apple/data.txt")
# True(解析后是同一个文件)六、常用模式
6.1 获取文件扩展名
python
import os.path
def get_extension(filepath):
_, ext = os.path.splitext(filepath)
return ext.lower()
get_extension("photo.jpg") # '.jpg'
get_extension("archive.tar.gz") # '.gz'
get_extension("Makefile") # ''6.2 替换扩展名
python
import os.path
def change_extension(filepath, new_ext):
root, _ = os.path.splitext(filepath)
return root + new_ext
change_extension("data.txt", ".json") # 'data.json'
change_extension("photo.jpg", ".png") # 'photo.png'6.3 遍历目录找特定文件
python
import os
import os.path
def find_files(directory, ext):
"""查找指定目录下所有特定扩展名的文件"""
result = []
for root, dirs, files in os.walk(directory):
for f in files:
if f.endswith(ext):
result.append(os.path.join(root, f))
return result
# 找到所有Python文件
py_files = find_files(".", ".py")6.4 安全地创建目录
python
import os
import os.path
def ensure_dir(path):
"""确保目录存在,不存在则创建"""
if not os.path.exists(path):
os.makedirs(path, exist_ok=True)
ensure_dir("data/2026/06")6.5 获取脚本所在目录
python
import os.path
# 获取当前脚本的绝对路径
script_path = os.path.abspath(__file__)
# 获取脚本所在目录
script_dir = os.path.dirname(script_path)
# 常用:相对于脚本位置读取配置
config_path = os.path.join(script_dir, "config.json")七、与pathlib的对比
os.path是函数式风格,pathlib是面向对象风格。功能上等价:
python
# os.path风格
import os.path
path = os.path.join("data", "file.txt")
exists = os.path.exists(path)
name = os.path.basename(path)
# pathlib风格
from pathlib import Path
path = Path("data") / "file.txt"
exists = path.exists()
name = path.name如果你的项目是新写的,推荐用pathlib。如果是维护老代码,os.path完全够用。
八、总结
os.path的核心就是路径的拼接、拆分、检查、转换:
| 分类 | 常用函数 |
|---|---|
| 拼接 | join() |
| 拆分 | basename(), dirname(), split(), splitext(), splitdrive() |
| 检查 | exists(), isfile(), isdir(), islink(), isabs() |
| 转换 | abspath(), realpath(), normpath(), relpath(), expanduser(), expandvars() |
| 信息 | getsize(), getmtime(), getatime(), getctime(), samefile() |
记住join()、exists()、basename()、dirname()、splitext()这五个,就能覆盖80%的场景。